#ifndef STL_STRINGS_H
#define STL_STRINGS_H
#include <cstring>
#include <ostream>
#include <vector>
#include <algorithm>

#define MAX_SHORTSTRING_LENGTH 256
#define INVALID_INDEX -1

class CString {
    enum eol_t { eol_cr, eol_lf, eol_crlf };
  protected:
    std::string m_String;
    eol_t m_eol_type;
  public:
    std::string& GetString( void );
    std::string GetString( void ) const;
    char *GetCString( void ) const;
    int GetLength( void ) const;
    bool IsEmpty( void ) const;
    CString& SetLength( void );
    CString& SetLength( const int Length );
    CString& Clear( void );
    char GetChar( const int Index ) const;
    char GetFirstChar( void ) const;
    char GetLastChar( void ) const;
    void SetChar( const int Index, const char Value );
    CString& Assign( const char AChar );
    CString& Assign( const char *AString );
    CString& Assign( const std::string& AString );
    CString& Assign( const CString& AString );
    CString& Append( const char AChar );
    CString& Append( const char *AString );
    CString& Append( const std::string& AString );
    CString& Append( const CString& AString );
    CString& AppendCR( void );
    CString& AppendLF( void );
    CString& AppendCRLF( void );
    CString& AppendEOL( void );
    CString  GetEOL( void );
    CString& SetEOL( const eol_t EndOfLine );
    char& operator []( const int Index );
    char operator []( const int Index ) const;
    CString& operator =( const char AChar );
    CString& operator =( const char *AString );
    CString& operator =( const std::string& AString );
    CString& operator =( const CString& AString );
    CString& operator =( const int AInteger );
    CString& operator =( const long long int AInteger );
    CString& operator =( const float AFloat );
    CString& operator =( const double AFloat );
    CString& operator +=( const char AChar );
    CString& operator +=( const char *CString );
    CString& operator +=( const CString& AString );
    CString& operator +=( const int AInteger );
    CString& operator +=( const long long int AInteger );
    CString& operator +=( const float AFloat );
    CString& operator +=( const double AFloat );
    bool operator ==( const char *AString ) const;
    bool operator ==( const std::string& AString ) const;
    bool operator ==( const CString& AString ) const;
    int GetInteger( void ) const;
    double GetFloat( void ) const;
    void Fill( const char AChar );
    void Print( std::ostream& out );
  public:
    CString( void );
    CString( const char AChar );
    CString( const char *AString );
    CString( const std::string& AString );
    CString( const CString& AString );
    ~CString( void );
};

class CStringList {
  protected:
    std::vector<CString *> m_Strings;
    CString m_NullString;
  protected:
    bool ValidIndex( const int Index ) const;
  public:
    bool IsEmpty( void ) const;
    int GetCount( void ) const;
    int GetLength( void ) const;
    CString& GetString( const int Index );
    CString GetString( const int Index ) const;
    CString Join( const CString& Delimiter ) const;
    int FindString( const CString& AString ) const;
    int Insert( const CString *AString );
    int Insert( const CString& AString );
    CStringList& Insert( const CStringList& AStringList );
    CStringList& InsertAt( const int Index, const CStringList& AStringList );
    CStringList& InsertAt( const int Index, const CString *AString );
    CStringList& InsertAt( const int Index, const CString& AString );
    CStringList& RemoveAt( const int Index );
    CStringList& RemoveEmpty( void );
    CStringList& RemoveDuplicates( void );
    CStringList& Clear( void );
    bool AppendFromFile( const CString& FileName );
    bool LoadFromFile( const CString& FileName );
    bool SaveToFile( const CString& FileName );
    void Print( std::ostream& out );
    CStringList& operator =( const CString& AString );
    CStringList& operator =( const CStringList& AStringList );
    CString& operator []( const int Index );
    CString operator []( const int Index ) const;
    CStringList& operator <<( const CString& AString );
  public:
    CStringList( void );
    CStringList( const CStringList& AStringList );
    ~CStringList( void );
};

#define CHARSET_SIZE (1<<(8*sizeof(char)))

class CCharset {
  protected:
    bool m_Charset[CHARSET_SIZE];
    CString m_Alphabet;
  protected:
    void UpdateCharset( void );
    void UpdateAlphabet( void );
  public:
    bool Isset( const char AChar ) const;
    char GetChar( const char AChar ) const;
    void SetChar( const char AChar );
    void UnsetChar( const char AChar );
    CString GetAlphabet( void ) const;
    void SetAlphabet( const CString& Alphabet );
    void Print( std::ostream& out );
  public:
    CCharset( void );
    CCharset( const CCharset& Charset );
    CCharset( const CString& Alphabet );
    ~CCharset( void );
};

class CCharIterator {
  protected:
    char m_NullChar;
  public:
    virtual int FirstPosition( void ) { return 0; }
    virtual int ThisPosition( void ) { return 0; }
    virtual int LastPosition( void ) { return 0; }
    //
    virtual char& First( void ) { return m_NullChar; }
    virtual char& Prev( void ) { return m_NullChar; }
    virtual char& This( void ) { return m_NullChar; }
    virtual char& Next( void ) { return m_NullChar; }
    virtual char& Last( void ) { return m_NullChar; }
    virtual void Reset( void ) {};
    virtual bool Match( const CString& Pattern, const bool Move = false );
    virtual void Print( std::ostream& out ) { ( void )out; };
  public:
    CCharIterator( void ) { m_NullChar = 0; };
    CCharIterator( const CCharIterator& ACharIterator ) { ( void )ACharIterator; m_NullChar = 0; };
    virtual ~CCharIterator( void ) {};
};

class CStringIterator: public CCharIterator {
  protected:
    CString *m_String;
    int m_Position;
  public:
    virtual int FirstPosition( void );
    virtual int ThisPosition( void );
    virtual int LastPosition( void );
    //
    virtual char& First( void );
    virtual char& Prev( void );
    virtual char& This( void );
    virtual char& Next( void );
    virtual char& Last( void );
    virtual void Reset( void );
    virtual bool Match( const CString& Pattern, const bool Move = false );
  public:
    CStringIterator( void );
    CStringIterator( const CString *AString );
    CStringIterator( const CStringIterator& AStringIterator );
    virtual ~CStringIterator( void ) {};
};

class CStringListIterator: public CCharIterator {
  protected:
    CStringList *m_StringList;
    int m_Line;
    int m_Position;
  public:
    virtual int FirstPosition( void );
    virtual int ThisPosition( void );
    virtual int LastPosition( void );
    //
    virtual char& First( void );
    virtual char& Prev( void );
    virtual char& This( void );
    virtual char& Next( void );
    virtual char& Last( void );
    virtual void Reset( void );
    virtual bool Match( const CString& Pattern, const bool Move = false );
  public:
    CStringListIterator( void );
    CStringListIterator( const CStringList *AStringList );
    CStringListIterator( const CStringListIterator& AStringListIterator );
    virtual ~CStringListIterator( void ) {};
};

static const unsigned int MAX_CHAR_FREQUENCY = ( ( 1 << ( 7 * sizeof( unsigned int ) ) ) - 1 );

class CCharHistogram {
  private:
    static const unsigned int FLAG_PURE_NUMERIC  = 0x00000001;
    static const unsigned int FLAG_PURE_INTEGER  = 0x00000002;
    static const unsigned int FLAG_ASCII_TEXT    = 0x00000004;
    static const unsigned int FLAG_CUSTOM_BINARY = 0x00000008;
  protected:
    unsigned int m_Histogram[CHARSET_SIZE];
    unsigned int m_Flags;
  protected:
    void Analyze( void );
  public:
    void Reset( void );
    void Insert( const char AChar );
    void Insert( const CString& AString );
    void Insert( const CStringList& AStringList );
    void Remove( const char AChar );
    void Remove( const CString& AString );
    void Remove( const CStringList& AStringList );
    bool IsPureNumeric( void );
    bool IsPureInteger( void );
    bool IsAsciiText( void );
    bool IsCustomBinary( void );
    unsigned int GetAt( const char AChar ) const;
    void SetAt( const char AChar, const unsigned int Frequency );
    CString GetAlphabet( void ) const;
    void Print( std::ostream& out );
  public:
    CCharHistogram( void );
    CCharHistogram( const CCharHistogram& AHistogram );
    ~CCharHistogram( void );
};

static const CString ALPHABET_NULL_CHAR      = char( 0x00 );
static const CString ALPHABET_TAB_CHAR       = char( 0x09 );
static const CString ALPHABET_CR_CHAR        = char( 0x0d );
static const CString ALPHABET_LF_CHAR        = char( 0x0a );
static const CString ALPHABET_NUMBER         = "0123456789";
static const CString ALPHABET_INTEGER_NUMBER = "+-0123456789";
static const CString ALPHABET_FLOAT_NUMBER   = "+-.,0123456789eE";
static const CString ALPHABET_DOUBLE_NUMBER  = "+-.,0123456789dD";
static const CString ALPHABET_REAL_NUMBER    = "+-.,0123456789eEdD";
static const CString ALPHABET_HEX_NUMBER     = "0123456789abcdefABCDEF";
static const CString ALPHABET_CTL_CHARS      = "\'\"\?\\\a\b\f\n\r\t\v\0";
static const CString ALPHABET_ESC_SEQUENCE   = "\'\"?\\abfnrtv0";
static const CString ALPHABET_SHELL_CHARS    = " !@#$%^&*(){}[];\'\"\\|<>?";

static const char HEX_CHARS_UCASE[17] = "0123456789ABCDEF";
static const char HEX_CHARS_LCASE[17] = "0123456789abcdef";

inline CString operator +( const CString& AString, const CString& BString )
{ CString result( AString ); result += BString; return result; }

inline CString operator +( const CString& AString, const char BChar )
{ CString result( AString ); result += BChar; return result; }

inline CString operator +( const char AChar, const CString& BString )
{ CString result( AChar ); result += BString; return result; }

inline CString operator +( const CString& AString, const int BInteger )
{ CString result( AString ); result += BInteger; return result; }

inline CString operator +( const int AInteger, const CString& BString )
{ CString result; result += AInteger; result += BString; return result; }

inline CString operator +( const CString& AString, const float BFloat )
{ CString result( AString ); result += BFloat; return result; }

inline CString operator +( const float AFloat, const CString& BString )
{ CString result; result += AFloat; result += BString; return result; }

inline CString operator +( const CString& AString, const double BFloat )
{ CString result( AString ); result += BFloat; return result; }

inline CString operator +( const double AFloat, const CString& BString )
{ CString result; result += AFloat; result += BString; return result; }

inline CString operator +( const CString& AString, const char *BCString )
{ CString result( AString ); result += BCString; return result; }

inline CString operator +( const char *AString, const CString& BString )
{ CString result( AString ); result += BString; return result; }



inline CString UpperCase( const CString& AString ) {
  CString result;
  result.SetLength( AString.GetLength() );
  for( int i = 0, n = AString.GetLength(); i < n; i++ ) {
    char c = AString[i];
    result[i] = islower( c ) ? toupper( c ) : c;
  }
  return result;
}

inline CString LowerCase( const CString& AString ) {
  CString result;
  result.SetLength( AString.GetLength() );
  for( int i = 0, n = AString.GetLength(); i < n; i++ ) {
    char c = AString[i];
    result[i] = isupper( c ) ? tolower( c ) : c;
  }
  return result;
}

inline char hexChar( const unsigned char Value ) {
  return HEX_CHARS_LCASE[Value & 0xF];
}

inline char HexChar( const unsigned char Value ) {
  return HEX_CHARS_UCASE[Value & 0xF];
}

inline CString hex( const unsigned int AInteger, const unsigned int Length = 8 ) {
  CString result;
  result.SetLength( Length );
  unsigned int value = AInteger;
  for( unsigned int i = 0, j = Length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_LCASE[value & 0xF];
    value >>= 4;
  }
  return result;
}

inline CString Hex( const unsigned int AInteger, const unsigned int Length = 8 ) {
  CString result;
  result.SetLength( Length );
  unsigned int value = AInteger;
  for( unsigned int i = 0, j = Length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_UCASE[value & 0xF];
    value >>= 4;
  }
  return result;
}

inline CString hex8( const unsigned char AInteger ) {
  return hex( AInteger, 2 * sizeof( unsigned char ) );
}

inline CString Hex8( const unsigned char AInteger ) {
  return Hex( AInteger, 2 * sizeof( unsigned char ) );
}

inline CString hex16( const unsigned short int AInteger ) {
  return hex( AInteger, 2 * sizeof( unsigned short int ) );
}

inline CString Hex16( const unsigned short int AInteger ) {
  return Hex( AInteger, 2 * sizeof( unsigned short int ) );
}

inline CString hex32( const unsigned int AInteger ) {
  return hex( AInteger, 2 * sizeof( unsigned int ) );
}

inline CString Hex32( const unsigned int AInteger ) {
  return Hex( AInteger, 2 * sizeof( unsigned int ) );
}

inline CString hex64( const long long int AInteger, const unsigned int Length = 16 ) {
  CString result;
  result.SetLength( Length );
  long long int value = AInteger;
  for( unsigned int i = 0, j = Length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_LCASE[( unsigned int )value & 0xF];
    value >>= 4;
  }
  return result;
}

inline CString Hex64( const long long int AInteger, const unsigned int Length = 16 ) {
  CString result;
  result.SetLength( Length );
  long long int value = AInteger;
  for( unsigned int i = 0, j = Length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_UCASE[( unsigned int )value & 0xF];
    value >>= 4;
  }
  return result;
}

inline CString hex( const unsigned char *Buffer, const unsigned int Length = 0 ) {
  unsigned int length = Length * 2;
  CString result;
  result.SetLength( length );
  for( unsigned int i = 0, j = length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_UCASE[Buffer[i] & 0xF];
    result[--j] = HEX_CHARS_UCASE[( Buffer[i] >> 4 ) & 0xF];
  }
  return result;
}

inline CString Hex( const unsigned char *Buffer, const unsigned int Length = 0 ) {
  unsigned int length = Length * 2;
  CString result;
  result.SetLength( length );
  for( unsigned int i = 0, j = length; i < Length; i++ ) {
    result[--j] = HEX_CHARS_UCASE[Buffer[i] & 0xF];
    result[--j] = HEX_CHARS_UCASE[( Buffer[i] >> 4 ) & 0xF];
  }
  return result;
}

CString StringOfChars( const char AChar, const int Count );
CString FillStr( const CString& Prefix, const char AChar, const CString& Suffix, const int Length );
CString EnumStr( const CString& Prefix, const int Counter,
                 const CString& Suffix, const unsigned int Length );
CString SignStr( const int Signature );
CString SubStr( const CString& AString, const int FirstPos, const int LastPos );
CString ShiftStr( const CString& AString, const int Shift );
void SplitStr( const CString& AString, const int Position, CString& LString, CString& RString );
CString JoinStr( const CString& AString, const CString& BString, const char Separator );
CString LeftStr( const CString& AString, const int Position );
CString RightStr( const CString& AString, const int Position );
CString FilterStr( const CString& AString, const CCharset& ValidChars,
                   const CCharset& InvalidChars, const bool ValidateUndefined );
int CountChars( const CString& AString, const char AChar );
int NextCharPos( const CString& AString, const char AChar, const int Position );
int PrevCharPos( const CString& AString, const char AChar, const int Position );
int FirstCharPos( const CString& AString, const char AChar );
int LastCharPos( const CString& AString, const char AChar );
CString TrimStr( const CString& AString );
CString LeadStr( const CString& AString, const unsigned int RLength );
void ParseStr( const CString& AString, const CString& Delimiters, CStringList& SubStrings );
void ParseStr( const CString& AString, const char Delimiter, CStringList& SubStrings );
CString CollectStr( const CStringList& SubStrings, const CString& Delimiters );
CString StripDupChars( const CString& AString, const char AChar );
CString StripDupChars( const CString& AString );
CString CheckFirstChar( const CString& AString, const char AChar );
CString CheckLastChar( const CString& AString, const char AChar );
int FindStr( const CString& AString, const CString& BString );
CString FindReplaceChar( const CString& AString, const char SearchChar,
                         const char ReplaceChar );
CString FindReplaceStr( const CString& AString, const CString& SearchString,
                        const CString& ReplaceString );
int ParseMemSizeStr( const CString& AString, int& UnitSize, char& UnitChar );
int ParseMemSizeStr( const CString& AString );
long long int ParseMemSizeStr64( const CString& AString,
                                 long long int& UnitSize, char& UnitChar );
long long int ParseMemSizeStr64( const CString& AString );
int GuessStr( const CString& AString, const CStringList& Variants,
              CString& Guessed, const bool TryFuzzy = false );
int GuessStr( const CString& AString, const CString& Variants, CString& Guessed,
              const bool TryFuzzy = false );
CString VariantStr( const int Index, const CString& Variants, const char Delimiter = ' ' );
CString MemSizeStr( const long long int Value, long long int& UnitSize, CString& UnitSuffix );
CString MemSizeStr( const long long int Value );
CString SI_UnitStr( const double Value, double& UnitSize,
                    CString& UnitPrefix, CString& UnitSymbol );
CString SI_UnitStr( const double Value );
bool IsQuoted( const CString& AString );
CString QuoteStr( const CString& AString );
CString UnquoteStr( const CString& AString );
CString ShieldSpaces( const CString& AString );
CString UnshieldSpaces( const CString& AString );
CString ShieldChars( const CString& AString, const CString& Chars );
CString UnshieldChars( const CString& AString, const CString& Chars );

#endif

